// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

import FoldAssembler from "./FoldAssembler";

export enum ESplitType {
    Horizontal,
    Vertical,
}


const {
    ccclass,
    requireComponent,
    property,
    executeInEditMode,
    disallowMultiple,
} = cc._decorator;


@ccclass
@executeInEditMode
@disallowMultiple
export default class Flexible extends cc.RenderComponent {
    @property({ type: cc.SpriteAtlas, visible: true, editorOnly: true, animatable: false })
    private _atlas: cc.SpriteAtlas = null;
    // @property({type:cc.SpriteAtlas, visible: true, editorOnly:true, animatable:false})
    // get atlas():cc.SpriteAtlas {
    //     return this._atlas;
    // }
    // set atlas(val:cc.SpriteAtlas) {
    //     this._atlas = val;
    // }

    @property({ type: cc.SpriteFrame })
    private _spriteFrame: cc.SpriteFrame = null;
    @property({ type: cc.SpriteFrame })
    get spriteFrame(): cc.SpriteFrame {
        return this._spriteFrame;
    }
    set spriteFrame(value: cc.SpriteFrame/*, force:boolean*/) {
        let lastSprite = this._spriteFrame;
        if (CC_EDITOR) {
            if (((lastSprite && lastSprite['_uuid']) === (value && value['_uuid']))) {
                return;
            }
        }
        else {
            if (lastSprite === value) {
                return;
            }
        }
        this._spriteFrame = value;
        this._applySpriteFrame(lastSprite);

        if (CC_EDITOR) {
            this.node.emit('spriteframe-changed', this);
        }
    }

    @property({ type: cc.Sprite.SizeMode, animatable: false })
    private _sizeMode: cc.Sprite.SizeMode = cc.Sprite.SizeMode.TRIMMED;
    @property({ type: cc.Sprite.SizeMode, animatable: false })
    get sizeMode(): cc.Sprite.SizeMode {
        return this._sizeMode;
    }
    set sizeMode(value: cc.Sprite.SizeMode) {
        this._sizeMode = value;
        if (value !== cc.Sprite.SizeMode.CUSTOM) {
            this._applySpriteSize();
        }
    }

    @property({ type: cc.Enum(ESplitType) })
    private _splitType: ESplitType = ESplitType.Vertical;
    @property({ type: cc.Enum(ESplitType) })
    get splitType(): ESplitType {
        return this._splitType;
    }
    set splitType(val: ESplitType) {
        if (this._splitType === val) return;
        this._splitType = val;
        this.setVertsDirty();
    }

    @property({min:0, max:1, slide:true})
    private _splitPercent:number = 0.5;

    @property({min:0, max:1, slide:true})
    get splitPercent(): number {
        return this._splitPercent;
    }
    set splitPercent(val: number) {
        val = Math.max(Math.min(val, 1), 0);
        if(val != this._splitPercent) {
            this._splitPercent = val;
            this.setVertsDirty();
        }
    }

    @property
    private _radAPage:number = Math.PI;

    get radAPage():number {
        return this._radAPage;
    }
    set radAPage(val:number) {
        val = Math.max(Math.min(val, Math.PI), 0);
        if(val != this._radAPage) {
            this._radAPage = val;
            this.setVertsDirty();
        }
    }

    @property({min:0, max:180, slide:true})
    get degAPage():number {
        return 180 - cc.misc.radiansToDegrees(this._radAPage);
    }
    set degAPage(val:number) {
        val = cc.misc.degreesToRadians(180 - val);
        this.radAPage = val;
    }


    @property
    private _radBPage:number = 0;

    get radBPage():number {
        return this._radBPage;
    }
    set radBPage(val:number) {
        val = Math.max(Math.min(val, Math.PI), 0);
        if(val != this._radBPage) {
            this._radBPage = val;
            this.setVertsDirty();
        }
    }


    @property({min:0, max:180, slide:true})
    get degBPage():number {
        return cc.misc.radiansToDegrees(this._radBPage);
    }
    set degBPage(val:number) {
        val = cc.misc.degreesToRadians(val);
        this.radBPage = val;
    }


    private get assembler() {
        return this["_assembler"];
    }

    private set assembler(val) {
        this["_assembler"] = val;
    }

    constructor() {
        super();

        this.assembler = new FoldAssembler();
    }

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        // super.onLoad();
        CC_EDITOR && this.node.on(cc.Node.EventType.SIZE_CHANGED, this._resizedInEditor, this);
        // this._applySpriteFrame(this._spriteFrame);
    }

    // override onDestroy
    onDestroy() {
        this.node.off(cc.Node.EventType.SIZE_CHANGED, this._resizedInEditor, this);

        super.onDestroy();
    };


    // start() {

    // }

    private _step = 0.01;

    update(dt) {
        if(CC_EDITOR) return;
        this['setVertsDirty']();
        if(this._radAPage >= Math.PI) this._step = -this._step;
        else if(this._radAPage <= Math.PI / 2) this._step = -this._step;
        
        this.radAPage += this._step;
    }


    setVertsDirty() {
        super['setVertsDirty']();
    }


    private _updateColor() {
        super['_updateColor']();
    }

    private disableRender() {
        super['disableRender']();
    }


    private _resetAssembler() {
        // Assembler.init(this);
        this._updateColor();
        // this.setVertsDirty();
    }


    private _updateMaterial() {
        // make sure material is belong to self.
        let material = this.getMaterial(0);
        if (material) {
            let texture = this._spriteFrame && this._spriteFrame.getTexture();

            if (material.getDefine('USE_TEXTURE') !== undefined) {
                if (texture) {
                    material.define('USE_TEXTURE', true);
                }
                else {
                    material.define('USE_TEXTURE', false);
                }
            }

            if (texture)
                material.setProperty('texture', texture);

            if (material.getDefine('CC_USE_MODEL') !== undefined) {
                material.define('CC_USE_MODEL', true);
            }
        }

        // cc.BlendFunc.prototype['_updateMaterial'].call(this);
    }

    private _applySpriteSize() {
        if (!this._spriteFrame || !this.isValid) return;

        if (cc.Sprite.SizeMode.RAW === this._sizeMode) {
            let size = this._spriteFrame.getOriginalSize();;
            this.node.setContentSize(size);
        } else if (cc.Sprite.SizeMode.TRIMMED === this._sizeMode) {
            let rect = this._spriteFrame.getRect();
            this.node.setContentSize(rect.width, rect.height);
        }

        // this['setVertsDirty']();
        this.setVertsDirty();
    }

    private _applyAtlas = CC_EDITOR && function (spriteFrame) {
        // Set atlas
        if (spriteFrame && spriteFrame._atlasUuid) {
            let self = this;
            cc.assetManager.loadAny(spriteFrame._atlasUuid, function (err, asset) {
                self._atlas = asset;
            });
        } else {
            this._atlas = null;
        }
    }

    private _applySpriteFrame(oldFrame: cc.SpriteFrame) {
        let oldTexture = oldFrame && oldFrame.getTexture();
        if (oldTexture && !oldTexture.loaded) {
            oldFrame.off('load', this._applySpriteSize, this);
        }

        this._updateMaterial();
        let spriteFrame = this._spriteFrame;
        if (spriteFrame) {
            let newTexture = spriteFrame.getTexture();
            if (newTexture && newTexture.loaded) {
                this._applySpriteSize();
            }
            else {
                // this.disableRender();
                this.disableRender();
                spriteFrame.once('load', this._applySpriteSize, this);
            }
        }
        else {
            // this.disableRender();
            this.disableRender();
        }

        if (CC_EDITOR) {
            // Set atlas
            this._applyAtlas(spriteFrame);
        }
    }

    private _resizedInEditor() {
        if (this._spriteFrame) {

            let actualSize = this.node.getContentSize();
            let expectedW = actualSize.width;
            let expectedH = actualSize.height;

            if (this._sizeMode === cc.Sprite.SizeMode.RAW) {
                let size = this._spriteFrame.getOriginalSize();
                expectedW = size.width;
                expectedH = size.height;
            }
            else if (this._sizeMode === cc.Sprite.SizeMode.TRIMMED) {
                let rect = this._spriteFrame.getRect();
                expectedW = rect.width;
                expectedH = rect.height;
            }

            if (expectedW !== actualSize.width || expectedH !== actualSize.height) {
                this._sizeMode = cc.Sprite.SizeMode.CUSTOM;
            }
        }
    }
}
